<?php
/*
 * 
 * Created on 2007-12-05
 * Project: pl.blacksoft.tomusdrw.core
 * Filename: ./core/conf/table_files.php
 * Author: Tomusdrw tomusdrw@blacksoft.pl
 * 		   tomusdrw.blacksoft.pl
 * 
 */
/*	
 * Obsługa plików
 */

if (!defined('FILE_SPACER'))
	define('FILE_SPACER', '*;'); //rozdzielacz poszczegolnych komorek
if (!defined('SPACER'))
	define('SPACER', '*\;'); //na co sie ma zamienic jak go znajda w tekscie:)

class table extends Ctable implements Itable {
	public $name;
	private $v ;//, $core;

	public function __construct($table_name, $cols_name=0, $tryb='silent') {
		$this->v = $tryb;
		global $_table_cols;
		$cols = $_table_cols;
		if (!file_exists(CONF_TABLE_PREFIX.$table_name)) { //plik nie istnieje
			$asdasd=((!empty($cols_name))?$cols_name:str_replace('/','_',$table_name));
			if (isset($cols[$asdasd])) { //znamy nazwy kolumn
				if ($plik=@fopen(CONF_TABLE_PREFIX.$table_name, "w+")) {
					//blokuejmy plik na wylacznosc
					flock($plik, LOCK_EX);
					//zapisujemy kolumny
					$tab=explode(', ',$cols[$asdasd]);
					for($i=0;$i<count($tab)-1;$i++) {
						fwrite($plik, substr($tab[$i],0,strpos($tab[$i],' ')).FILE_SPACER);
					}
					fwrite($plik,substr($tab[count($tab)-1],0,strpos($tab[count($tab)-1],' '))."\n");
					//odblokowac plik
					flock($plik, LOCK_UN);
					fclose($plik);
					$this->debug('table_no_file', null, DBG_WARN, 2);
				} else $this->debug('table_no_file_cant', $table_name);
			} else {
			$this->debug('table_no_file_no_cols', $table_name);
			}
		}
		$this->name=CONF_TABLE_PREFIX.$table_name;
	}
	
	public function get($limit=0, $sort='', $order=0, $typ='assoc') { //pobiera cala tabele
		if (file_exists($this->name))
			$plik =@ file ($this->name);
		if (isset($plik)&&$plik) {
			$a=array();
			$x = explode(FILE_SPACER, chop($plik[0]));
			if ($typ=='headers') 
				return $x;
				
			$count = count($plik);
			for ($i=1; $i<$count;$i++) {
				$tab = explode(FILE_SPACER, chop($plik[$i]));
				$ile = count($tab);
				if ($typ!='assoc'||$typ=='row') {
					for($asd=0;$asd<$ile;$asd++) {
						$tab[$asd]=str_replace(SPACER, FILE_SPACER, $tab[$asd]);
					}
				}
				if ($typ!='row'||$typ=='assoc') {
					for($z=0; $z<$ile;$z++) {
						$tab[$x[$z]]=str_replace(SPACER, FILE_SPACER, $tab[$z]);
					}
				}
				$a[count($a)]=$tab;
			}
			unset($plik);
			if ($sort!=='') $this->sort($a, $sort, $order);
			if ($limit>0) {
				$ile = count($a)-1;
				$min = ($ile-$limit<0)?0:$ile-$limit;
				for ($i=$ile;$i>$min; $i--) {
					$ret[]=$a[$i];
				}
			} else {
				$ret = $a;
			}
			unset($a);
			return $ret;
		}
	//	if ($this->v!=='silent')
	$this->debug('table_file_cannot_open', $this->name);
		return 1;
	}
	
	public function insert($dane) { //dopisuje dane na koniec tablicy
		//pobieram wszystkie rekordy 
		$tablica = $this->get();
		if (is_array($tablica)) {
			$simple=false;
			foreach ($dane as $v) {
				if (!is_array($v)) {$simple=true; break; }
			}
			if ($simple)
				$tablica[]=$dane;
			else {
				foreach ($dane as $v) {
					$tablica[]=$v;
				}
			}
			return $this->save($tablica);
		}
	}
	
	public function save($dane) { //zapisuje dane zwraca 0->wszystko ok 1->niepoprawne dane
		if (is_array($dane)) {
			$headers=$this->get(0,'',0, 'headers');
			
			//zapisujemy plik
			//przygotowywujemy dane do zapisu
			$msg=implode(FILE_SPACER, $headers)."\n"; //zapisalismy naglowek
			$ile = count($dane);
			$id=array();
			for ($i=0;$i<$ile;$i++) {
				if (isset($dane[$i]['id'])&&is_numeric($dane[$i]['id']))
					$id[$dane[$i]['id']]=1;
			}
			for ($i=0; $i<$ile; $i++) {
				if (!isset($dane[$i]['id'])||$dane[$i]['id']==""||$dane[$i]['id']=="auto") {
					$z=-1;
					while($z++<100000) {
						if (!isset($id[$z])) {
							$dane[$i]['id']=$z;
							break;
						}
					}
				}
				foreach($headers as $k) {
					if (!isset($dane[$i][$k])) {
						$dane[$i][$k] = "auto";
					}
					if ($dane[$i][$k]==='auto') {
						for ($z=0;$z<$ile;$z++) {
							$tab[]=(int)$dane[$z][$k];
						}
						sort($tab);
						$dane[$i][$k]=$tab[count($tab)-1]+1;
						unset($tab);
					}
					$msg.=str_replace(FILE_SPACER, SPACER, nonl(chop($dane[$i][$k])));
					$msg.=FILE_SPACER;
				}
				$msg=substr($msg,0,strlen($msg)-2); //obcinamy ostatni filespacer
				//dodajemy znak konca lini jesli to nie jest ostatni wiersz
				if ($i+1<$ile) { 
						$msg.="\n";
				}
			}
			//wrzucamy to wszystko do pliku
			if (@file_put_contents($this->name, $msg, LOCK_EX)) {
			//	if ($this->v!=='silent'&&$this->v!=='error_only')
				$this->debug('table_changes_saved', null, DBG_INFO, 3);
				return 0;
			}
		//	if ($this->v!=='silent')
			$this->debug('table_file_cant_write', $this->name);
			return 2; //nie znaleziono pliku lub nie mozna do niego zapisac!:P
		}
	//	if ($this->v!=='silent')
		$this->debug('table_wrong_input');
		return 1;
	}
	
	private function compare($var, $op) {
		//print_r($var);
		//print_r($op);
		switch ($op) {
			case '>': return ($var[0]>$var[1])?1:0;
			case '=': return ($var[0]==$var[1])?1:0; 
			case '!=': return ($var[0]!=$var[1])?1:0;
			case '<': return ($var[0]<$var[1])?1:0;
			case '>=': return ($var[0]>=$var[1])?1:0;
			case '<=': return ($var[0]<=$var[1])?1:0;
			case 'BEETWEEN': return ((($var[0]>=$var[1])&&($var[0]<=$var[2]))||(($var[0]<=$var[1])&&($var[0]>=$var[2])))?1:0;
			case 'LIKE': return (substr_count($var[0],$var[1]))?1:0;
			default: return 0;
		}
	}
	
	public function select($kolumny,$wartosci,$operatory='=', $limit=0) {
		$cols=$this->get();
		$end=array();
		if (is_array($kolumny)&&is_array($wartosci)&&(is_array($operatory)||$operatory==='=')&&(count($kolumny)==count($wartosci))) {
			foreach ($cols as $col) {
				$count=0;
				$ile = count($kolumny);
				for ($i=0; $i<$ile; $i++) {
					if ($this->compare(array($col[$kolumny[$i]],$wartosci[$i]), ((isset($operatory[$i]))?($operatory[$i]):((is_array($operatory))?$operatory[count($operatory)-1]:$operatory)))) {
						$count++;
					}
				}
				if ($count==count($kolumny)) {
					$end[count($end)]=$col;
				}
			}
		} elseif (!is_array($kolumny)&&!is_array($wartosci)&&!is_array($operatory)) {
			if (is_array($cols))
				foreach ($cols as $col) {
					if ($this->compare(array($col[$kolumny],$wartosci),$operatory)) {
						$end[count($end)]=$col;
					}
				}
		} else {
	//		if ($this->v!=='silent')
		$this->debug('table_wrong_input');
			return 1;
		}
		if ($limit>0) {
			$ile = count($end)-1;
			$min = ($ile-$limit<0)?0:$ile-$limit;
			for ($i=$ile;$i>$min; $i--) {
				$ret[]=$end[$i];
			}
		} else {
			$ret = $end;
		}
		unset($end);
		return $ret;
	}
		
	public function update($kolumny, $wartosci, $operatory='=', $dane) {
		$cols=$this->get();
		$end=array();
		if (is_array($kolumny)&&is_array($wartosci)&&(is_array($operatory)||$operatory==='=')&&(count($kolumny)==count($wartosci))) {
			foreach ($cols as $col) {
				$count=0;
				for ($i=0; $i<count($kolumny); $i++) {
					if (!$this->compare(array($col[$kolumny[$i]],$wartosci[$i]), (isset($operatory[$i]))?$operatory[$i]:$operatory)) {
						$count++;
					}
				}
				if ($count==count($kolumny)) {
					$end[count($end)]=$col;
				}
			}
		} elseif (!is_array($kolumny)&&!is_array($wartosci)&&!is_array($operatory)) {
			foreach ($cols as $col) {
				if (!$this->compare(array($col[$kolumny],$wartosci),$operatory)) {
					$end[count($end)]=$col;
				}
			}
		} else {
	//		if ($this->v!=='silent')
		$this->debug('table_wrong_input');
			return 1;
		}		
		//dopisuje na koniec
		foreach ($dane as $d) {
			$end[count($end)]=$d;
		}
		return $this->save($end);
		//zapisane bez wycietych rekordow
	}
	
	public function delete($kolumny, $wartosci, $operatory='=') {
		$cols=$this->get();
		$end=array();
		if (is_array($kolumny)&&is_array($wartosci)&&(is_array($operatory)||$operatory==='=')&&(count($kolumny)==count($wartosci))) {
			foreach ($cols as $col) {
				$count=0;
				for ($i=0; $i<count($kolumny); $i++) {
					if (!$this->compare(array($col[$kolumny[$i]],$wartosci[$i]), (isset($operatory[$i]))?$operatory[$i]:$operatory)) {
						$count++;
					}
				}
				if ($count==count($kolumny)) {
					$end[]=$col;
				}
			}
		} elseif (!is_array($kolumny)&&!is_array($wartosci)&&!is_array($operatory)) {
			foreach ($cols as $col) {
				if (!$this->compare(array($col[$kolumny],$wartosci),$operatory)) {
					$end[]=$col;
				}
			}
		} else {
		//	if ($this->v!=='silent')
			$this->debug('table_wrong_input');
			return 1;
		}
		if ($end==$cols) {
		//	if ($this->v!=='silent'&&$this->v!=='error_only')
			$this->debug('table_no_changes', null, DBG_INFO, 3);
			return 3; //nic sie nie zmienilo
		}
		return $this->save($end);	
	}
}

define ('FTABLE', true);


/**
 * Other method for file support
 * @author Karol Kuczok (karol@kuczok.net)
 * @link http://www.kuczok.net/
 * 
 */

class db {
		
	private static $db_dir=CONF_TABLE_PREFIX;
	private static $separator='*;';
	private static $separator_user='*\;';
	private static $allowed_operators=array('=','<','>','<=','>=','LIKE','!=');
	
	private static $restricted_words=array(
		"\n" => '!next!!-!line!',
		"\r" => '!karetka-!+back!',
	);
	
	public static function getQueryCount() {
		return self::$count_queries;
	}
	
	public static function create($table,$struct) {
		/**
		 * @todo by sprawdzala poprawność aktualnej tabeli i w razie potrzeby poprawiała
		 */
		foreach ($struct as $k => $v) {
			switch($v) {
				case 'INT': $struct[$k]='INT'; break;
				case 'INT 0': case 'INT0': $struct[$k]='INT0'; break;
				case 'INT 1': case 'INT1': $struct[$k]='INT1'; break;
				case 'VARCHAR': $struct[$k]='TEXT'; break;
				default: $struct[$k]='TEXT'; break;
			}
		}
		$struct=array_merge(array('id'=>'INT'),$struct);
		if (is_file(self::$db_dir.$table)) return true;
		$data="1\n";
		foreach ($struct as $k => $v) {
			//nie interesuje nas typ pola właściwie :d
			$data.=$k.':'.$v.self::$separator;
		}
		file_put_contents(self::$db_dir.$table,$data);
		return true;
		
	}
	public static function insert($table,$row) {
		$rows=self::load($table);
		
		$file=file(self::$db_dir.$table);
		$row['id']=(int)self::nonl($file[0]);
		
		$rows[]=$row;
		self::save($table,$rows,1);
		return $row['id'];
	}
	
	private static function getId($table) {
		$file=file(self::$db_dir.$table);
		return self::nonl($file[0]);
	}
	
	public static function listTables() {
		$h=dir(self::$db_dir);
		$tables=array();
		while ($fn=readdir($h)) {
			if (is_file(self::$db_dir.$fn)) $tables[]=$fn;
		}
		return $tables;
	}
	
	public static function getRowCount($table) {
		$rows=self::load($table);
		return count($rows);
	}
	
	public static function getColumns($table) {
		$file=file(self::$db_dir.$table);
		$columns=explode(self::$separator,self::nonl($file[1]));
		return $columns;
	}
	
	private static function nonl($tekst) {
 		return str_replace(array("\n\r", "\n", "\r"), "", $tekst);
	}
	
	private static function save($table,$rows,$idmod=0) {
		$file=file(self::$db_dir.$table);
		$cols=explode(self::$separator,self::nonl($file[1]));
		$columns_type=array();
		$columns=array();
		foreach ($cols as $v) {
			if (empty($v)) break;
			unset ($tmp);
			$tmp=explode(':',$v);
			$columns[]=$tmp[0];
			$columns_type[]=$tmp[1];
		}
		unset ($cols,$tmp);
		$tmp=((int)(self::nonl($file[0]))+$idmod)."\n".self::nonl($file[1]);
		foreach ($rows as $row) {
			$tmp.="\n";
			foreach ($columns as $k => $col) {
				$col=self::nonl($col);
				if (!empty($col)) {
					if (isset($row[$col])) {
						$text=$row[$col];
						//jeszcze dodadjemy restricted
						$zamien_z=array();
						$zamien_na=array();
						foreach (self::$restricted_words as $k => $v) {
							$zamien_z[]=$k;
							$zamien_na[]=$v;
						}
						$text=str_replace($zamien_z,$zamien_na,$text);
						
						$tmp.=str_replace(self::$separator,self::$separator_user,$text).self::$separator;
						
					} else {
						switch ($columns_type[$k]) {
							case 'INT':
							case 'INT0': $tmp.='0'.self::$separator; break;
							case 'INT1': $tmp.='1'.self::$separator; break;
							default: $tmp.=' '.self::$separator; break;
						}
					}
				}
			}
		}
		file_put_contents(self::$db_dir.$table,$tmp);
	}
	
	private static function load($table) {
		$file=file(self::$db_dir.$table);
		$rows=array();
		$cols=explode(self::$separator,self::nonl($file[1]));
		$columns_type=array();
		$columns=array();
		foreach ($cols as $v) {
			if (empty($v)) break;
			unset ($tmp);
			$tmp=explode(':',$v);
			$columns[]=$tmp[0];
			$columns_type[]=$tmp[1];
		}
		unset ($cols,$tmp);
		foreach ($file as $k => $v) {
			if ($k>1) {
				$i=0;
				$tmp=explode(self::$separator,$v);
				unset ($row); $row=array();
				foreach ($columns as $val) {
					$val=self::nonl($val);
					if (!empty($val)) {
						$text=$tmp[$i++];
						//jeszcze dodadjemy restricted
						$zamien_z=array();
						$zamien_na=array();
						foreach (self::$restricted_words as $k => $v) {
							$zamien_z[]=$v;
							$zamien_na[]=$k;
						}
						$text=str_replace($zamien_z,$zamien_na,$text);
						
						$row[$val]=str_replace(self::$separator_user,self::$separator,$text);
					}
				}
				$rows[]=$row;
			}
		}
		return $rows;
	}
	
	private static function isAllowedOperator($op) {
		if (in_array($op,self::$allowed_operators)) return true;
		else return false;
	}
	
	private static function compare($var, $op) {
		if (!self::isAllowedOperator($op)) trigger_error('Niedozwolony operator: '.$operator,E_USER_ERROR);
		switch ($op) {
			case '>': return ($var[0]>$var[1])?true:false;
			case '=': return ($var[0]==$var[1])?true:false; 
			case '!=': return ($var[0]!=$var[1])?true:false;
			case '<': return ($var[0]<$var[1])?true:false;
			case '>=': return ($var[0]>=$var[1])?true:false;
			case '<=': return ($var[0]<=$var[1])?true:false;
			case 'LIKE': return (substr_count($var[0],$var[1]))?true:false;
			default: return false;
		}
	}
	
	public static function update($table,$newrow,$field,$operator,$value) {
		$rows=self::load($table);
		
		if (is_array($field) && is_array($operator) && is_array($value)) {
			foreach ($rows as $k => $row) {
				$i=0;
				foreach ($field as $fk => $fv) {
					if (self::compare(array($row[$fv],$value[$fk]),$operator[$fk])==true) $i++;
					else break;
				}
				if ($i==count($field)) {
					//zgadza się
					$rows[$k]=array_merge($row,$newrow);
					
				}	
			}
			
		} elseif (!is_array($field) && !is_array($operator) && !is_array($value)) {
			foreach ($rows as $k => $row) {
				if (self::compare(array($row[$field],$value),$operator)==true) {
					$rows[$k]=array_merge($row,$newrow);
				}
			}
		}
		
		//teraz to trzeba jakoś zapisać cały ten plik?
		self::save($table,$rows);
		
		return true; // bo sprawdza?
	}
	
	
	public static function delete($table,$field,$operator,$value) {
		$rows=self::load($table);
		
		if (is_array($field) && is_array($operator) && is_array($value)) {
			foreach ($rows as $k => $row) {
				$i=0;
				foreach ($field as $fk => $fv) {
					if (self::compare(array($row[$fv],$value[$fk]),$operator[$fk])==true) $i++;
					else break;
				}
				if ($i==count($field)) {
					//zgadza się
					unset ($rows[$k]);
					
				}	
			}
			
		} elseif (!is_array($field) && !is_array($operator) && !is_array($value)) {
			foreach ($rows as $k => $row) {
				//if (!in_array($field,$row)) return false;
				if (self::compare(array($row[$field],$value),$operator)==true) {
					unset ($rows[$k]);
				}
			}
		}
		
		
		self::save($table,$rows);
		
		return true;
	}

	public static function select($table,$field,$operator,$value,$order='',$order_type='',$limit=-1) {
		$rows=self::load($table);
		$return_rows=array();
		if (is_array($field) && is_array($operator) && is_array($value)) {
			foreach ($rows as $k => $row) {
				$i=0;
				foreach ($field as $fk => $fv) {
					if (self::compare(array($row[$fv],$value[$fk]),$operator[$fk])==true) $i++;
					else break;
				}
				if ($i==count($field)) {
					//zgadza się
					$return_rows[]=$row;
					
				}
			}
			
		} elseif (!is_array($field) && !is_array($operator) && !is_array($value)) {
			foreach ($rows as $k => $row) {
				//if (!in_array($field,$row)) return false;
				if (self::compare(array($row[$field],$value),$operator)==true)
					$return_rows[]=$row;
			}
		} elseif (!is_array($field) && !is_array($operator) && is_array($value)) {
			foreach ($rows as $k => $row) {
				foreach($value as $tempval) {
					if (self::compare(array($row[$field],$tempval),$operator)==true) {
						$return_rows[]=$row;
						break; //idziemy sprawdzać następny rowek
					}
				}
			}
			
		}
		
		//sortowanie
		if (strlen($order)>0) {
			if (count($return_rows)>0 && isset($return_rows[0][$order])) {
				//jest sens sortować ;s
				foreach ($return_rows as $k => $v) $order_list[$k]=$v[$order];
				if ($order_type=='DESC') {
					array_multisort($order_list,SORT_DESC,SORT_REGULAR,$return_rows);
				} else {
					array_multisort($order_list,SORT_ASC,SORT_REGULAR,$return_rows);
				}
			}		
		}
		
		//limit
		if ($limit!=-1) {
			//jeszcze musimy trochę pokombinować w sensie tylko określoną ilość zwrócić
			$tmp_i=0;
			$tmp_array=array();
			foreach ($return_rows as $k => $v) {
				$tmp_i++;
				$tmp_array[]=$v;
				if ($tmp_i==$limit) break;
			}
			$return_rows=$tmp_array;
			unset ($tmp_array);
			unset ($tmp_i);
		}
		
		return $return_rows;
	}

	
}

?>